#!/usr/local/bin/python
from __future__ import print_function
from xlrd import *
import sys

class xml_node:
    def __init__(self,name="",dname="",type="",num="",value="",idx=0,width=0):
        self.name = name
        self.dname = dname
        self.type = type
        self.num = num
        self.value = value
        self.idx = idx
        self.width = width
        self.children = []
    def _add_child(self,child):
        self.children.append(child)
    def _is_option(self):
        if self.num == "*" or self.num == "?":
            return True
        return False
    def _is_mul(self):
        return self.num == "+"
    def _is_virtual(self):
        if self.type == "@elem" and self.num == "":
            if len(self.children) == 1 and self.children[0].type == "@elem":
                return True
        return False
    def _is_del(self):
        if self.type == "@attr" or self.type == "@value":
            return True
        return False
    def _get_size(self):
        height = 0
        if len(self.children):
            height = 1
        for node in self.children:
            h = node._get_size()
            if h > height:
                height = h
        height +=1

        return height
    def _get_width(self):
        return self.width
    def _is_null(self):
        if not self.value == "":
            return False
        for node in self.children:
            if not node._is_null():
                return False
        return True
    def _print(self):
        print("name = %s " % self.name,end="")
        print("dname = %s " % self.dname,end="")
        print("type = %s " % self.type,end="")
        print("num = %s " % self.num,end="")
        if type(self.value) == float:
            print("value = %d " % int(self.value),end="")
        else:
            print("value = %s " % self.value,end="")
        print("idx = %d" % self.idx)
        print("width = %s " % self.width)
                
        for node in self.children:
                        node._print()
def get_max_col(sheet,row,col,max_col):
    for c in range(col+1,max_col):
        cell = sheet.cell(row,c)
        if cell.ctype != XL_CELL_BLANK and cell.ctype != XL_CELL_EMPTY:
            return c-1
    return max_col

def get_max_row(sheet,row,col,max_row):
    for r in range(row+1,max_row+1):
        cell = sheet.cell(r,col)
        if cell.ctype != XL_CELL_BLANK and cell.ctype != XL_CELL_EMPTY:
            return r-1
    return max_row

def is_null_cell(cell):
    if cell.ctype == XL_CELL_BLANK or cell.ctype == XL_CELL_EMPTY:
        return True
    return False

def get_next_startr(sheet,start_r,end_r,col):
    if start_r > end_r:
        return None
    if is_null_cell(sheet.cell(start_r,col)):
        return None
    max_r = get_max_row(sheet,start_r,col,end_r)
    if max_r+1 > end_r:
        return None
    return max_r+1
        
def create_metadata(sheet,start_r,end_r,col,max_col):
    if col > max_col:
        return None
    
    max_row=get_max_row(sheet,start_r,col,end_r)
    if(is_null_cell(sheet.cell(start_r,col))):
        return None
    name = sheet.cell(start_r,col).value
    dname = sheet.cell(start_r,col+1).value
    type_num = sheet.cell(start_r,col+2).value
    if type_num.endswith(("+","?","*")):
        type=type_num[0:len(type_num)-1]
        num=type_num[len(type_num)-1:len(type_num)]
    else:
        type=type_num
        num=""
    
    node = xml_node(name,dname,type,num)
    
    c_col = col+3
    
    c_row = start_r
    while   c_row != None and c_col <= max_col:
        sub_node = create_metadata(sheet,c_row,max_row,c_col,max_col)
        if sub_node != None:
            node._add_child(sub_node)
            node.width += sub_node.width
        c_row = get_next_startr(sheet,c_row,max_row,c_col)

    if node._is_del():
        node.width += 1
                
    return node
def get_no_op_child_idx(meta_node):
    idx = 0
    for node in meta_node.children:
            if node._is_del():
                    if node._is_option():
                            idx+=1
                    else:
                            return idx
            else:
                    idx += get_no_op_child_idx(node)
                    if not node._is_option():
                            return idx
    return idx
def replace_idx(string,idx):
    if string.find("$0") != -1:
        return string.replace("$0",str(idx))
    elif string.find("$1") != -1:
        return string.replace("$1",str(idx+1))
    return string
def create_data(sheet,meta_node,data_node,start_r,end_r,start_c,ismul=False):
    end_c = start_c + meta_node._get_width()-1

    if meta_node.type == "@attr":
            data_node._add_child(xml_node(meta_node.name,meta_node.dname,meta_node.type,"",sheet.cell(start_r,start_c).value))
    elif meta_node.type == "@value":
            data_node._add_child(xml_node(meta_node.name,meta_node.dname,meta_node.type,"",sheet.cell(start_r,start_c).value))
    elif meta_node.type == "@elem":
            if ismul:
                if meta_node._is_virtual():
                    sub_data_node = xml_node(meta_node.name,meta_node.dname,meta_node.type,"","")
                    data_node._add_child(sub_data_node)
                    create_data(sheet,meta_node.children[0],sub_data_node,start_r,end_r,start_c,True)
                else:
                    idx = get_no_op_child_idx(meta_node)
                    cc = start_c+idx
                    rr_s = start_r
                    rr_e = get_max_row(sheet,rr_s,cc,end_r)
                    i=0
                    while rr_s <= end_r:
                            sub_data_node = xml_node(meta_node.name,meta_node.dname,meta_node.type,"","",i)
                            data_node._add_child(sub_data_node)
                            create_data(sheet,meta_node,sub_data_node,rr_s,rr_e,start_c)
                            rr_s = rr_e+1
                            rr_e = get_max_row(sheet,rr_s,cc,end_r)
                            i += 1
            else:
                    for s in meta_node.children:
                         create_data(sheet,s,data_node,start_r,end_r,start_c,True)
                         start_c += s._get_width()
def iconv(s,encoding):
    if type(s) != unicode:
        return s

    return s.encode(encoding)
def print_nstr(str,num):
    if num <= 1:
        return
    for i in range(1,num):
        print(str,end="")
def xml_begin_left(name,lev,idx=0):
    print_nstr("\t",lev)
    print("<%s" % replace_idx(name,idx),end="")
def xml_begin_right(nl=True):
    if nl:
	print(">")
    else:
    	print(">",end="")
def xml_end(name,lev,idx=0):
    print_nstr("\t",lev)
    print("</%s>" % replace_idx(name,idx))
def xml_attr(name,value,encoding):
    if type(value) == float:
        print(" %s=\"%d\"" % (name,int(value)),end="")
    elif value != "":
        print(" %s=\"%s\"" % (name),iconv(value,encoding),end="")
def xml_value(name,value,lev,encoding):
    if value != "":
        xml_begin_left(name,lev)
        xml_begin_right(False)
        if type(value) == float:
            print("%d" % int(value),end="")
        else:
	    new_value = iconv(value,encoding)
            print("%s" % new_value,end="")
        xml_end(name,0)
def data_to_xml(data_node,lev,encoding):
    flag = False
    if lev == 0:
	print("<?xml version=\"1.0\" encoding=\"%s\"?>" % encoding)
        pass 
    else:
        if(data_node.type == "@attr"):
            xml_attr(data_node.dname,data_node.value,encoding)
        elif(data_node.type == "@value"):
            xml_value(data_node.dname,data_node.value,lev,encoding)
        elif(data_node.type == "@elem"):
            xml_begin_left(data_node.dname,lev,data_node.idx)
            flag = True
    for node in data_node.children:
        if not node._is_null():
            if node.type == "@attr":
                data_to_xml(node,lev+1,encoding)
    if flag:
        xml_begin_right()
    for node in data_node.children:
        if not node._is_null():
            if node.type != "@attr":
                data_to_xml(node,lev+1,encoding)
    if flag:
        xml_end(data_node.dname,lev,data_node.idx)
if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("Usage %s excel_path encoding" % sys.argv[0])
        sys.exit(1)
    in_file = sys.argv[1]
    encodeing = sys.argv[2]
    
    
    book = open_workbook(in_file,formatting_info=True)
    sheet_data = book.sheet_by_name("data")
    sheet_metadata = book.sheet_by_name("metadata")

    metadata_root = create_metadata(sheet_metadata,0,sheet_metadata.nrows-1,0,sheet_metadata.ncols-1)
    h = metadata_root._get_size()
    data_root = xml_node("root","root")
    create_data(sheet_data,metadata_root,data_root,h,sheet_data.nrows-1,0,True)
    data_to_xml(data_root,0,encodeing)
